<?php

class Crud_Db_Table_Row
{
	/**
	 * @var Crud_Db_Table
	 */
	protected $_table;
	
	/**
	 * @var Zend_Db_Table_Row
	 */
	protected $_row;
	
	/**
	 * Changed columns array.
	 * 
	 * @var array
	 */
	protected $_changedColumns = array();
	
	/**
	 * Create wrapper for Db row.
	 * 
	 * @param Zend_Db_Table_Row $row
	 * @return void
	 */
	public function __construct(Crud_Db_Table $table, Zend_Db_Table_Row_Abstract $row)
	{
		$this->_table = $table;
		$this->_row = $row;
	}
	
	/**
	 * Call wrapped row methods.
	 * 
	 * @param string $method
	 * @param array $args
	 * @return mixed
	 */
	public function __call($method, $args)
	{
		return call_user_func_array(array($this->getRow(), $method), $args);
	}
	
	/**
	 * Return parent Crud_Db_Table.
	 * 
	 * @return Crud_Db_Table_Abstract
	 */
	public function getTable()
	{
		return $this->_table;
	}
	
	/**
	 * Return wrapped row.
	 * 
	 * @return Zend_Db_Table_Row_Abstract
	 */
	public function getRow()
	{
		return $this->_row;
	}
	
	/**
	 * Return column value.
	 * 
	 * @param string $column
	 * @return mixed
	 */
	public function getColumnValue($column)
	{
		if ($column instanceof Crud_Db_Table_Column) {
			$column = $column->getName();
		}
		return $this->getRow()->__get($column);
	}
	
	/**
	 * Set column value.
	 * 
	 * @param string $column
	 * @param mixed $value
	 * @return void
	 */
	public function setColumnValue($column, $value)
	{
		if ($column instanceof Crud_Db_Table_Column) {
			$column = $column->getName();
		}
		return $this->getRow()->__set($column, $value);
	}
	
	/**
	 * Return true when id is not set.
	 * 
	 * @return boolean
	 */
	public function isNew()
	{
		return !$this->getColumnValue('id');
	}
	
    /**
     * Deletes existing rows.
     * Also delete many2many rows.
     * 
     * @return integer Number of affected rows
     */
	public function delete()
	{
		$table = $this->getTable();
		$m2ms = $table->getMany2ManyTables();
		
		$affected = 0;
		foreach ($m2ms as $m2m) {
			$affected += $this->deleteMany2Many($m2m);
		}
		
		$affected += $this->getRow()->delete();
		return $affected;
	}
	
	/**
	 * Create many2many rows by given table and values of 3rd column.
	 * @param Crud_Db_Table $m2m
	 * @param array $values
	 * @return void
	 */
	public function createMany2manyRows(Crud_Db_Table $m2m, array $values)
	{
		$table = $this->getTable();
		$column = $m2m->getFKColumnFor($table);
		$column3rd = $m2m->getFKColumnNotFor($table);
	
		foreach ($values as $value) {
			$m2mRow = $m2m->createRow();
			$m2mRow->setColumnValue($column->getName(), $this->getColumnValue('id'));
			$m2mRow->setColumnValue($column3rd->getName(), $value);
			$m2mRow->save();
		}
	}
	
	/**
	 * Delete many2many table entryes with reference to current row.
	 * 
	 * @param Crud_Db_Table $m2m
	 * @return integer Affected rows.
	 */
	public function deleteMany2Many(Crud_Db_Table $m2m)
	{
		$table = $this->getTable();
		$row = $this->getRow();
		
		$column = $m2m->getFKColumnFor($table);
	
		// Select all rows from m2m table by current table id
		$select = $m2m->select();
		$name = $column->getName();
		$select->where("`$name` = ?", $this->getColumnValue('id'));
		$rowset = $m2m->fetchAll($select);
		
		// And delete all selected rows
		$affected = 0;
		foreach ($rowset as $m2mRow) {
			$m2mRow->delete();
			$affected++;
		}
		
		return $affected;
	}
	
	/**
	 * Process form and update column values.
	 * Also delete old and create new many2many entryes.
	 * 
	 * @param Crud_Form $form
	 * @return void
	 */
	public function setForm(Crud_Form $form)
	{
		$data = $form->getValues();
		$table = $this->getTable();

		// Set value for each column
		foreach ($data as $key => $value) {
			if (!$table->issetColumn($key)) {
				continue;
			}
			
			// Skip value if that unchange.
			$v = $form->getUnfilteredValue($key);
			
			$element = $form->getElement($key);
			if ($element instanceof Zend_Form_Element_File) {
				if (!$element->isReceived()) {
					$element->receive();
				}
				
				// Set content of file
				if (!$element->getFileName()) {
					continue;
				}
				
				$name = $element->getUploadName();
				$v = $value = $name;
			}
			
			if ($v == $this->getColumnValue($key)) {
				continue;
			}
			
			$this->_changedColumns[] = $key;
			$this->setColumnValue($key, $value);
		}
		
		$action = ($this->isNew()) ? 'add entry in' : 'modify';
		$this->save();
		$this->log($action);
			
		// Create dependent many2many rows.
		$m2ms = $table->getMany2ManyTables();
		foreach ($m2ms as $name => $m2m) {
			if (!isset($data[$name])) {
				continue;
			}
			
			if (!$this->isNew()) {
				$this->deleteMany2Many($m2m);
			}
			
			$this->createMany2ManyRows($m2m, $data[$name]);
		}
	}
	
	/**
	 * Adding to log. 
	 * 
	 * @return void
	 */
	public function log($action = 'modify')
	{
		// Recursieve gone xD
		if ($this->_row instanceof AdminLogRow) {
			return;
		}
		
		$tableName = $this->getTable()->getTableName();
		$columns = implode('; ', $this->_changedColumns);
		$count = count($this->_changedColumns);
		$rowId = $this->getId();
		
		$peer = AdminLogPeer::getInstance();
		$row = $peer->createRow();
		$row->setChangedTable($tableName);
		$row->setChangedColumns($columns);
		$row->setChangedRow($rowId);
		
		
		
		$user = Zend_Auth::getInstance()->getIdentity();
		$user = AdminUserPeer::getInstance()->findByLogin($user)->current();
		
		$tableTag = "<a href='/admin/crud/list/table/$tableName'>$tableName</a>";
		
		if ($action == 'delete') {
			$message = "User `{$user->getLogin()}` delete entry with id `$rowId` from `$tableTag`";
		} else {
			$message = "User `{$user->getLogin()}` $action `$tableTag` (id=<a href='/admin/crud/edit/table/$tableName/id/$rowId'>$rowId</a>)";
			if ($action == 'modify') {
				 $message .= " ($count cols changed)";
			}
		}
		
		$row->setLog($message);
		$row->setUserId($user->getId());
		$row->save();
	}
	
}
